This is a composition of these patches for Firefox 60:

https://bugzilla.mozilla.org/show_bug.cgi?id=1441873
https://bugzilla.mozilla.org/show_bug.cgi?id=1441665
https://bugzilla.mozilla.org/show_bug.cgi?id=1456898
https://bugzilla.mozilla.org/show_bug.cgi?id=1457309
https://bugzilla.mozilla.org/show_bug.cgi?id=1457691

which fix popup window placement at CSD window mode.


diff --git a/widget/gtk/nsLookAndFeel.cpp b/widget/gtk/nsLookAndFeel.cpp
--- a/widget/gtk/nsLookAndFeel.cpp
+++ b/widget/gtk/nsLookAndFeel.cpp
@@ -1076,19 +1076,18 @@ nsLookAndFeel::EnsureInit()
                          nullptr);
 
     GetSystemFontInfo(gtk_widget_get_style_context(entry),
                       &mFieldFontName, &mFieldFontStyle);
 
     gtk_widget_destroy(window);
     g_object_unref(labelWidget);
 
-    // Require GTK 3.10 for GtkHeaderBar support and compatible window manager.
-    mCSDAvailable = (gtk_check_version(3, 10, 0) == nullptr &&
-        nsWindow::GetCSDSupportLevel() != nsWindow::CSD_SUPPORT_NONE);
+    mCSDAvailable =
+        nsWindow::GetSystemCSDSupportLevel() != nsWindow::CSD_SUPPORT_NONE;
 
     mCSDCloseButton = false;
     mCSDMinimizeButton = false;
     mCSDMaximizeButton = false;
 
     // We need to initialize whole CSD config explicitly because it's queried
     // as -moz-gtk* media features.
     WidgetNodeType buttonLayout[TOOLBAR_BUTTONS];
diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -395,28 +395,26 @@ public:
     // From GDK
     int GdkCoordToDevicePixels(gint coord);
     LayoutDeviceIntPoint GdkPointToDevicePixels(GdkPoint point);
     LayoutDeviceIntPoint GdkEventCoordsToDevicePixels(gdouble x, gdouble y);
     LayoutDeviceIntRect GdkRectToDevicePixels(GdkRectangle rect);
 
     virtual bool WidgetTypeSupportsAcceleration() override;
 
-    bool DoDrawTitlebar() const;
-
     typedef enum { CSD_SUPPORT_SYSTEM,    // CSD including shadows
                    CSD_SUPPORT_CLIENT,    // CSD without shadows
                    CSD_SUPPORT_NONE,      // WM does not support CSD at all
                    CSD_SUPPORT_UNKNOWN
     } CSDSupportLevel;
     /**
      * Get the support of Client Side Decoration by checking
      * the XDG_CURRENT_DESKTOP environment variable.
      */
-    static CSDSupportLevel GetCSDSupportLevel();
+    static CSDSupportLevel GetSystemCSDSupportLevel();
 
 protected:
     virtual ~nsWindow();
 
     // event handling code
     void DispatchActivateEvent(void);
     void DispatchDeactivateEvent(void);
     void DispatchResized();
@@ -512,19 +510,21 @@ private:
     int                 mXDepth;
     mozilla::widget::WindowSurfaceProvider mSurfaceProvider;
 #endif
 
     // Upper bound on pending ConfigureNotify events to be dispatched to the
     // window. See bug 1225044.
     unsigned int mPendingConfigures;
 
-    bool               mIsCSDAvailable;
+    // Window titlebar rendering mode, CSD_SUPPORT_NONE if it's disabled
+    // for this window.
+    CSDSupportLevel    mCSDSupportLevel;
     // If true, draw our own window titlebar.
-    bool               mIsCSDEnabled;
+    bool               mDrawInTitlebar;
     // Draggable titlebar region maintained by UpdateWindowDraggingRegion
     LayoutDeviceIntRegion mDraggableRegion;
 
 #ifdef ACCESSIBILITY
     RefPtr<mozilla::a11y::Accessible> mRootAccessible;
 
     /**
      * Request to create the accessible for this window if it is top level.

diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -474,18 +474,18 @@ nsWindow::nsWindow()
 
     mTransparencyBitmapWidth  = 0;
     mTransparencyBitmapHeight = 0;
 
 #if GTK_CHECK_VERSION(3,4,0)
     mLastScrollEventTime = GDK_CURRENT_TIME;
 #endif
     mPendingConfigures = 0;
-    mIsCSDAvailable = false;
-    mIsCSDEnabled = false;
+    mCSDSupportLevel = CSD_SUPPORT_NONE;
+    mDrawInTitlebar = false;
 }
 
 nsWindow::~nsWindow()
 {
     LOG(("nsWindow::~nsWindow() [%p]\n", (void *)this));
 
     delete[] mTransparencyBitmap;
     mTransparencyBitmap = nullptr;
@@ -2814,17 +2814,17 @@ nsWindow::OnButtonReleaseEvent(GdkEventB
     LayoutDeviceIntPoint pos = event.mRefPoint;
 
     nsEventStatus eventStatus = DispatchInputEvent(&event);
 
     bool defaultPrevented = (eventStatus == nsEventStatus_eConsumeNoDefault);
     // Check if mouse position in titlebar and doubleclick happened to
     // trigger restore/maximize.
     if (!defaultPrevented
-             && mIsCSDEnabled
+             && mDrawInTitlebar
              && event.button == WidgetMouseEvent::eLeftButton
              && event.mClickCount == 2
              && mDraggableRegion.Contains(pos.x, pos.y)) {
 
         if (mSizeState == nsSizeMode_Maximized) {
             SetSizeMode(nsSizeMode_Normal);
         } else {
             SetSizeMode(nsSizeMode_Maximized);
@@ -3758,22 +3758,18 @@ nsWindow::Create(nsIWidget* aParent,
             gtk_window_set_wmclass(GTK_WINDOW(mShell), "Toplevel",
                                    gdk_get_program_class());
 
             // each toplevel window gets its own window group
             GtkWindowGroup *group = gtk_window_group_new();
             gtk_window_group_add_window(group, GTK_WINDOW(mShell));
             g_object_unref(group);
 
-            int32_t isCSDAvailable = false;
-            nsresult rv = LookAndFeel::GetInt(LookAndFeel::eIntID_GTKCSDAvailable,
-                                              &isCSDAvailable);
-            if (NS_SUCCEEDED(rv)) {
-               mIsCSDAvailable = isCSDAvailable;
-            }
+            // We enable titlebar rendering for toplevel windows only.
+            mCSDSupportLevel = GetSystemCSDSupportLevel();
         }
 
         // Create a container to hold child windows and child GtkWidgets.
         GtkWidget *container = moz_container_new();
         mContainer = MOZ_CONTAINER(container);
 
         // "csd" style is set when widget is realized so we need to call
         // it explicitly now.
@@ -3788,17 +3784,17 @@ nsWindow::Create(nsIWidget* aParent,
          *    are drawn by Gtk+ to mShell. Content is rendered to mContainer
          *    and we listen to the Gtk+ events on mContainer.
          * 3) We're running on Wayland. All gecko content is rendered
          *    to mContainer and we listen to the Gtk+ events on mContainer.
          */
         GtkStyleContext* style = gtk_widget_get_style_context(mShell);
         drawToContainer =
             !mIsX11Display ||
-            (mIsCSDAvailable && GetCSDSupportLevel() == CSD_SUPPORT_CLIENT) ||
+            (mCSDSupportLevel == CSD_SUPPORT_CLIENT) ||
             gtk_style_context_has_class(style, "csd");
         eventWidget = (drawToContainer) ? container : mShell;
 
         gtk_widget_add_events(eventWidget, kEvents);
         if (drawToContainer)
             gtk_widget_add_events(mShell, GDK_PROPERTY_CHANGE_MASK);
 
         // Prevent GtkWindow from painting a background to avoid flickering.
@@ -6581,90 +6577,91 @@ nsWindow::ClearCachedResources()
             window->ClearCachedResources();
         }
     }
 }
 
 nsresult
 nsWindow::SetNonClientMargins(LayoutDeviceIntMargin &aMargins)
 {
-  SetDrawsInTitlebar(aMargins.top == 0);
-  return NS_OK;
+    SetDrawsInTitlebar(aMargins.top == 0);
+    return NS_OK;
 }
 
 void
 nsWindow::SetDrawsInTitlebar(bool aState)
 {
-  if (!mIsCSDAvailable || aState == mIsCSDEnabled)
-      return;
-
-  if (mShell) {
-      if (GetCSDSupportLevel() == CSD_SUPPORT_SYSTEM) {
-          SetWindowDecoration(aState ? eBorderStyle_border : mBorderStyle);
-      }
-      else {
-          /* Window manager does not support GDK_DECOR_BORDER,
-           * emulate it by CSD.
-           *
-           * gtk_window_set_titlebar() works on unrealized widgets only,
-           * we need to handle mShell carefully here.
-           * When CSD is enabled mGdkWindow is owned by mContainer which is good
-           * as we can't delete our mGdkWindow. To make mShell unrealized while
-           * mContainer is preserved we temporary reparent mContainer to an
-           * invisible GtkWindow.
-           */
-          NativeShow(false);
-
-          // Using GTK_WINDOW_POPUP rather than
-          // GTK_WINDOW_TOPLEVEL in the hope that POPUP results in less
-          // initialization and window manager interaction.
-          GtkWidget* tmpWindow = gtk_window_new(GTK_WINDOW_POPUP);
-          gtk_widget_realize(tmpWindow);
-
-          gtk_widget_reparent(GTK_WIDGET(mContainer), tmpWindow);
-          gtk_widget_unrealize(GTK_WIDGET(mShell));
-
-          // Available as of GTK 3.10+
-          static auto sGtkWindowSetTitlebar = (void (*)(GtkWindow*, GtkWidget*))
-              dlsym(RTLD_DEFAULT, "gtk_window_set_titlebar");
-          MOZ_ASSERT(sGtkWindowSetTitlebar,
-              "Missing gtk_window_set_titlebar(), old Gtk+ library?");
-
-          if (aState) {
-              // Add a hidden titlebar widget to trigger CSD, but disable the default
-              // titlebar.  GtkFixed is a somewhat random choice for a simple unused
-              // widget. gtk_window_set_titlebar() takes ownership of the titlebar
-              // widget.
-              sGtkWindowSetTitlebar(GTK_WINDOW(mShell), gtk_fixed_new());
-          } else {
-              sGtkWindowSetTitlebar(GTK_WINDOW(mShell), nullptr);
-          }
-
-          /* A workaround for https://bugzilla.gnome.org/show_bug.cgi?id=791081
-           * gtk_widget_realize() throws:
-           * "In pixman_region32_init_rect: Invalid rectangle passed"
-           * when mShell has default 1x1 size.
-           */
-          GtkAllocation allocation = {0, 0, 0, 0};
-          gtk_widget_get_preferred_width(GTK_WIDGET(mShell), nullptr,
-                                         &allocation.width);
-          gtk_widget_get_preferred_height(GTK_WIDGET(mShell), nullptr,
-                                          &allocation.height);
-          gtk_widget_size_allocate(GTK_WIDGET(mShell), &allocation);
-
-          gtk_widget_realize(GTK_WIDGET(mShell));
-          gtk_widget_reparent(GTK_WIDGET(mContainer), GTK_WIDGET(mShell));
-          mNeedsShow = true;
-          NativeResize();
-
-          gtk_widget_destroy(tmpWindow);
-      }
-  }
-
-  mIsCSDEnabled = aState;
+    if (!mShell ||
+        mCSDSupportLevel == CSD_SUPPORT_NONE ||
+        aState == mDrawInTitlebar) {
+        return;
+    }
+
+    if (mCSDSupportLevel == CSD_SUPPORT_SYSTEM) {
+        SetWindowDecoration(aState ? eBorderStyle_border : mBorderStyle);
+    }
+    else if (mCSDSupportLevel == CSD_SUPPORT_CLIENT) {
+        /* Window manager does not support GDK_DECOR_BORDER,
+         * emulate it by CSD.
+         *
+         * gtk_window_set_titlebar() works on unrealized widgets only,
+         * we need to handle mShell carefully here.
+         * When CSD is enabled mGdkWindow is owned by mContainer which is good
+         * as we can't delete our mGdkWindow. To make mShell unrealized while
+         * mContainer is preserved we temporary reparent mContainer to an
+         * invisible GtkWindow.
+         */
+        NativeShow(false);
+
+        // Using GTK_WINDOW_POPUP rather than
+        // GTK_WINDOW_TOPLEVEL in the hope that POPUP results in less
+        // initialization and window manager interaction.
+        GtkWidget* tmpWindow = gtk_window_new(GTK_WINDOW_POPUP);
+        gtk_widget_realize(tmpWindow);
+
+        gtk_widget_reparent(GTK_WIDGET(mContainer), tmpWindow);
+        gtk_widget_unrealize(GTK_WIDGET(mShell));
+
+        // Available as of GTK 3.10+
+        static auto sGtkWindowSetTitlebar = (void (*)(GtkWindow*, GtkWidget*))
+            dlsym(RTLD_DEFAULT, "gtk_window_set_titlebar");
+        MOZ_ASSERT(sGtkWindowSetTitlebar,
+            "Missing gtk_window_set_titlebar(), old Gtk+ library?");
+
+        if (aState) {
+            // Add a hidden titlebar widget to trigger CSD, but disable the default
+            // titlebar.  GtkFixed is a somewhat random choice for a simple unused
+            // widget. gtk_window_set_titlebar() takes ownership of the titlebar
+            // widget.
+            sGtkWindowSetTitlebar(GTK_WINDOW(mShell), gtk_fixed_new());
+        } else {
+            sGtkWindowSetTitlebar(GTK_WINDOW(mShell), nullptr);
+        }
+
+        /* A workaround for https://bugzilla.gnome.org/show_bug.cgi?id=791081
+         * gtk_widget_realize() throws:
+         * "In pixman_region32_init_rect: Invalid rectangle passed"
+         * when mShell has default 1x1 size.
+         */
+        GtkAllocation allocation = {0, 0, 0, 0};
+        gtk_widget_get_preferred_width(GTK_WIDGET(mShell), nullptr,
+                                       &allocation.width);
+        gtk_widget_get_preferred_height(GTK_WIDGET(mShell), nullptr,
+                                        &allocation.height);
+        gtk_widget_size_allocate(GTK_WIDGET(mShell), &allocation);
+
+        gtk_widget_realize(GTK_WIDGET(mShell));
+        gtk_widget_reparent(GTK_WIDGET(mContainer), GTK_WIDGET(mShell));
+        mNeedsShow = true;
+        NativeResize();
+
+        gtk_widget_destroy(tmpWindow);
+    }
+
+    mDrawInTitlebar = aState;
 }
 
 gint
 nsWindow::GdkScaleFactor()
 {
 #if (MOZ_WIDGET_GTK >= 3)
     // Available as of GTK 3.10+
     static auto sGdkWindowGetScaleFactorPtr = (gint (*)(GdkWindow*))
@@ -6923,28 +6920,28 @@ nsWindow::SynthesizeNativeTouchPoint(uin
   event.touch.y = DevicePixelsToGdkCoordRoundDown(pointInWindow.y);
 
   gdk_event_put(&event);
 
   return NS_OK;
 }
 #endif
 
-bool
-nsWindow::DoDrawTitlebar() const
-{
-    return mIsCSDEnabled && mSizeState == nsSizeMode_Normal;
-}
-
 nsWindow::CSDSupportLevel
-nsWindow::GetCSDSupportLevel() {
+nsWindow::GetSystemCSDSupportLevel() {
     if (sCSDSupportLevel != CSD_SUPPORT_UNKNOWN) {
         return sCSDSupportLevel;
     }
 
+    // Require GTK 3.10 for GtkHeaderBar support and compatible window manager.
+    if (gtk_check_version(3, 10, 0) != nullptr) {
+        sCSDSupportLevel = CSD_SUPPORT_NONE;
+        return sCSDSupportLevel;
+    }
+
     const char* currentDesktop = getenv("XDG_CURRENT_DESKTOP");
     if (currentDesktop) {
         // GNOME Flashback (fallback)
         if (strstr(currentDesktop, "GNOME-Flashback:GNOME") != nullptr) {
             sCSDSupportLevel = CSD_SUPPORT_CLIENT;
         // gnome-shell
         } else if (strstr(currentDesktop, "GNOME") != nullptr) {
             sCSDSupportLevel = CSD_SUPPORT_SYSTEM;
diff -up firefox-60.0/widget/gtk/gtk3drawing.cpp.orig firefox-60.0/widget/gtk/gtk3drawing.cpp
--- firefox-60.0/widget/gtk/gtk3drawing.cpp.orig	2018-04-26 22:07:36.000000000 +0200
+++ firefox-60.0/widget/gtk/gtk3drawing.cpp	2018-04-30 13:38:19.083949868 +0200
@@ -38,6 +38,16 @@ static ToolbarGTKMetrics sToolbarMetrics
 #define GTK_STATE_FLAG_CHECKED (1 << 11)
 #endif
 
+static GtkBorder
+operator+=(GtkBorder& first, const GtkBorder& second)
+{
+    first.left += second.left;
+    first.right += second.right;
+    first.top += second.top;
+    first.bottom += second.bottom;
+    return first;
+}
+
 static gint
 moz_gtk_get_tab_thickness(GtkStyleContext *style);
 
@@ -3056,6 +3066,76 @@ GetScrollbarMetrics(GtkOrientation aOrie
     return metrics;
 }
 
+/*
+ * get_shadow_width() from gtkwindow.c is not public so we need
+ * to implement it.
+ */
+bool
+GetCSDDecorationSize(GtkWindow *aGtkWindow, GtkBorder* aDecorationSize)
+{
+    GtkStyleContext* context = gtk_widget_get_style_context(GTK_WIDGET(aGtkWindow));
+    bool solidDecorations = gtk_style_context_has_class(context, "solid-csd");
+    context = GetStyleContext(solidDecorations ?
+                              MOZ_GTK_WINDOW_DECORATION_SOLID :
+                              MOZ_GTK_WINDOW_DECORATION);
+
+    /* Always sum border + padding */
+    GtkBorder padding;
+    GtkStateFlags state = gtk_style_context_get_state(context);
+    gtk_style_context_get_border(context, state, aDecorationSize);
+    gtk_style_context_get_padding(context, state, &padding);
+    *aDecorationSize += padding;
+
+    // Available on GTK 3.20+.
+    static auto sGtkRenderBackgroundGetClip =
+        (void (*)(GtkStyleContext*, gdouble, gdouble, gdouble, gdouble, GdkRectangle*))
+        dlsym(RTLD_DEFAULT, "gtk_render_background_get_clip");
+
+    GtkBorder margin;
+    gtk_style_context_get_margin(context, state, &margin);
+
+    GtkBorder extents = {0, 0, 0, 0};
+    if (sGtkRenderBackgroundGetClip) {
+        /* Get shadow extents but combine with style margin; use the bigger value.
+         */
+        GdkRectangle clip;
+        sGtkRenderBackgroundGetClip(context, 0, 0, 0, 0, &clip);
+
+        extents.top = -clip.y;
+        extents.right = clip.width + clip.x;
+        extents.bottom = clip.height + clip.y;
+        extents.left = -clip.x;
+
+        // Margin is used for resize grip size - it's not present on
+        // popup windows.
+        if (gtk_window_get_window_type(aGtkWindow) != GTK_WINDOW_POPUP) {
+            extents.top = MAX(extents.top, margin.top);
+            extents.right = MAX(extents.right, margin.right);
+            extents.bottom = MAX(extents.bottom, margin.bottom);
+            extents.left = MAX(extents.left, margin.left);
+        }
+    } else {
+        /* If we can't get shadow extents use decoration-resize-handle instead
+         * as a workaround. This is inspired by update_border_windows()
+         * from gtkwindow.c although this is not 100% accurate as we emulate
+         * the extents here.
+         */
+        gint handle;
+        gtk_widget_style_get(GetWidget(MOZ_GTK_WINDOW),
+                             "decoration-resize-handle", &handle,
+                             NULL);
+
+        extents.top = handle + margin.top;
+        extents.right = handle + margin.right;
+        extents.bottom = handle + margin.bottom;
+        extents.left = handle + margin.left;
+    }
+
+    *aDecorationSize += extents;
+
+    return (sGtkRenderBackgroundGetClip != nullptr);
+}
+
 /* cairo_t *cr argument has to be a system-cairo. */
 gint
 moz_gtk_widget_paint(WidgetNodeType widget, cairo_t *cr,
diff -up firefox-60.0/widget/gtk/gtkdrawing.h.orig firefox-60.0/widget/gtk/gtkdrawing.h
--- firefox-60.0/widget/gtk/gtkdrawing.h.orig	2018-04-26 22:07:35.000000000 +0200
+++ firefox-60.0/widget/gtk/gtkdrawing.h	2018-04-30 13:38:19.083949868 +0200
@@ -334,6 +334,10 @@ typedef enum {
    */
   MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE_RESTORE,
 
+  /* Client-side window decoration node. Available on GTK 3.20+. */
+  MOZ_GTK_WINDOW_DECORATION,
+  MOZ_GTK_WINDOW_DECORATION_SOLID,
+
   MOZ_GTK_WIDGET_NODE_COUNT
 } WidgetNodeType;
 
@@ -606,4 +610,17 @@ GetToolbarButtonMetrics(WidgetNodeType a
 int
 GetGtkHeaderBarButtonLayout(WidgetNodeType* aButtonLayout, int aMaxButtonNums);
 
+/**
+ * Get size of CSD window extents of given GtkWindow.
+ *
+ * aGtkWindow      [IN]  Decorated window.
+ * aDecorationSize [OUT] Returns calculated (or estimated) decoration
+ *                       size of given aGtkWindow.
+ *
+ * returns:    True if we have extract decoration size (for GTK 3.20+)
+ *             False if we have only an estimation (for GTK+ before  3.20+)
+ */
+bool
+GetCSDDecorationSize(GtkWindow *aGtkWindow, GtkBorder* aDecorationSize);
+
 #endif
diff -up firefox-60.0/widget/gtk/nsWindow.cpp.orig firefox-60.0/widget/gtk/nsWindow.cpp
--- firefox-60.0/widget/gtk/nsWindow.cpp.orig	2018-04-30 13:37:32.145122854 +0200
+++ firefox-60.0/widget/gtk/nsWindow.cpp	2018-04-30 13:39:12.593752681 +0200
@@ -127,6 +127,7 @@ using namespace mozilla::widget;
 #endif
 
 #include "nsShmImage.h"
+#include "gtkdrawing.h"
 
 #include "nsIDOMWheelEvent.h"
 
@@ -3360,6 +3361,10 @@ nsWindow::OnWindowStateEvent(GtkWidget *
           aEvent->new_window_state & GDK_WINDOW_STATE_FULLSCREEN);
       }
     }
+
+    if (mDrawInTitlebar && mCSDSupportLevel == CSD_SUPPORT_CLIENT) {
+        UpdateClientOffsetForCSDWindow();
+    }
 }
 
 void
@@ -6552,6 +6557,32 @@ nsWindow::ClearCachedResources()
     }
 }
 
+/* nsWindow::UpdateClientOffsetForCSDWindow() is designed to be called from
+ * paint code to update mClientOffset any time. It also propagates
+ * the mClientOffset to child tabs.
+ *
+ * It works only for CSD decorated GtkWindow.
+ */
+void
+nsWindow::UpdateClientOffsetForCSDWindow()
+{
+    // _NET_FRAME_EXTENTS is not set on client decorated windows,
+    // so we need to read offset between mContainer and toplevel mShell
+    // window.
+    if (mSizeState == nsSizeMode_Normal) {
+        GtkBorder decorationSize;
+        GetCSDDecorationSize(GTK_WINDOW(mShell), &decorationSize);
+        mClientOffset = nsIntPoint(decorationSize.left, decorationSize.top);
+    } else {
+        mClientOffset = nsIntPoint(0, 0);
+    }
+
+    // Send a WindowMoved notification. This ensures that TabParent
+    // picks up the new client offset and sends it to the child process
+    // if appropriate.
+    NotifyWindowMoved(mBounds.x, mBounds.y);
+}
+
 nsresult
 nsWindow::SetNonClientMargins(LayoutDeviceIntMargin &aMargins)
 {
@@ -6626,6 +6657,13 @@ nsWindow::SetDrawsInTitlebar(bool aState
         mNeedsShow = true;
         NativeResize();
 
+        // When we use system titlebar setup managed by Gtk+ we also get
+        // _NET_FRAME_EXTENTS property for our toplevel window so we can't
+        // update the client offset it here.
+        if (aState) {
+            UpdateClientOffsetForCSDWindow();
+        }
+
         gtk_widget_destroy(tmpWindow);
     }
 
diff -up firefox-60.0/widget/gtk/nsWindow.h.orig firefox-60.0/widget/gtk/nsWindow.h
--- firefox-60.0/widget/gtk/nsWindow.h.orig	2018-04-30 13:37:32.143122861 +0200
+++ firefox-60.0/widget/gtk/nsWindow.h	2018-04-30 13:38:19.085949861 +0200
@@ -454,6 +454,8 @@ private:
     nsIWidgetListener* GetListener();
     bool               IsComposited() const;
 
+    void               UpdateClientOffsetForCSDWindow();
+
     GtkWidget          *mShell;
     MozContainer       *mContainer;
     GdkWindow          *mGdkWindow;
diff -up firefox-60.0/widget/gtk/WidgetStyleCache.cpp.orig firefox-60.0/widget/gtk/WidgetStyleCache.cpp
--- firefox-60.0/widget/gtk/WidgetStyleCache.cpp.orig	2018-04-26 22:07:35.000000000 +0200
+++ firefox-60.0/widget/gtk/WidgetStyleCache.cpp	2018-04-30 13:38:19.085949861 +0200
@@ -1285,6 +1285,22 @@ GetCssNodeStyleInternal(WidgetNodeType a
           "MOZ_GTK_HEADER_BAR_BUTTON_RESTORE is used as an icon only!");
       return nullptr;
     }
+    case MOZ_GTK_WINDOW_DECORATION:
+    {
+      GtkStyleContext* parentStyle =
+          CreateSubStyleWithClass(MOZ_GTK_WINDOW, "csd");
+      style = CreateCSSNode("decoration", parentStyle);
+      g_object_unref(parentStyle);
+      break;
+    }
+    case MOZ_GTK_WINDOW_DECORATION_SOLID:
+    {
+      GtkStyleContext* parentStyle =
+          CreateSubStyleWithClass(MOZ_GTK_WINDOW, "solid-csd");
+      style = CreateCSSNode("decoration", parentStyle);
+      g_object_unref(parentStyle);
+      break;
+    }
     default:
       return GetWidgetRootStyle(aNodeType);
   }
